
#pragma once

// -----------------------------------------------------------------------------

#include <Winerror.h>
#include <Windows.h>
#include <Winbase.h>
#include "Win32.DateTime.h"
#include "Win32.String.h"
#include <list>

namespace Kif
{
namespace Win32
{
namespace Diagnostics
{

enum Verbosity
{
   Verbose_Unknown = 0,
   Verbose_Exceptions_Only = 1,
   Verbose_Trace = 2,
   Verbose_Transactions = 3,
   Verbose_None  = 4
}  ;  // end of Verbosity

enum LogOutputOption
{
   LogTo_Uknown = 0,
   LogTo_ConsoleOnly = 1,
   LogTo_ConsoleAndErrorLog = 2,
   LogTo_ErrorLogOnly = 3,
   LogTo_None = 4
}  ;  // end of LogOutputOption

enum SeverityLevel
{
   Severity_Unknown = 0,
   Severity_Fatal = 1,
   Severity_Warning = 2,
   Severity_Info = 3,
   Severity_None = 4
}  ;  // end of LogOutputOption

// -----------------------------------------------------------------------------

class Log
{
public:

   // --------------------------------------------------------------------------
   static void WriteLogFile(TCHAR *logPath, Kif::Win32::String &message);

   // --------------------------------------------------------------------------
   /// <summary>output given message to default device</summary>
   static void WriteMessage(
      TCHAR *logPath, TCHAR *location, TCHAR *message, SeverityLevel severity,
      LogOutputOption outputTo);
   static void WriteMessageToFile(
      TCHAR *logPath, TCHAR *location, TCHAR *message, SeverityLevel severity,
      LogOutputOption outputTo);

   static void WriteMessage(TCHAR *message, LogOutputOption outputTo)
   {  WriteMessage(NULL,Kif::Win32::String::GetEmptyString(),
         message,Severity_Fatal, outputTo);
   }  // end of WriteMessage

   static void WriteMessage(TCHAR *message)
   {  WriteMessage(NULL,Kif::Win32::String::GetEmptyString(),
         message,Severity_Fatal, LogTo_ConsoleAndErrorLog);
   }  // end of WriteMessage

   static void WriteMessage(TCHAR *location, TCHAR *message, HRESULT hResult);
   static void WriteMessage(TCHAR *message, HRESULT hResult)
   {
      WriteMessage(NULL,message,hResult);
   }  // end of WriteMessage

   static void WriteMessage(TCHAR *location, TCHAR *message)
   {  WriteMessage(NULL,location,
         message,Severity_Fatal, LogTo_ConsoleAndErrorLog);
   }  // end of WriteMessage

   static void ConsoleWriteMessage(TCHAR *message)
   {  WriteMessage(NULL,NULL,message,Severity_None, LogTo_ConsoleOnly);
   }  // end of WriteMessage

   static void ConsoleWriteMessage(Kif::Win32::String &message)
   {  WriteMessage(NULL,NULL,message.GetBuffer(),Severity_None, LogTo_ConsoleOnly);
   }  // end of WriteMessage

   static void ConsoleWriteMessage(Kif::Win32::String *message)
   {
      if (message == NULL)
         return;
      WriteMessage(NULL,NULL,message->GetBuffer(),Severity_None, LogTo_ConsoleOnly);
   }  // end of WriteMessage


   static Kif::Win32::String *ToXmlLogEntry(
      TCHAR *location, TCHAR *message, SeverityLevel severity);
   static Kif::Win32::String *ToXmlLogEntry(TCHAR *location, TCHAR *message)
   {
      return(ToXmlLogEntry(location,message,Severity_None));
   }  // end of ToXmlLogEntry
   static Kif::Win32::String *ToXmlLogEntry(TCHAR *message)
   {
      return(ToXmlLogEntry(NULL,message,Severity_None));
   }  // end of ToXmlLogEntry

   static Kif::Win32::String *GetSeverityString(SeverityLevel severity)
   {
      TCHAR SeverityUnknown[] = _T("Severity_Unknown");
      TCHAR SeverityFatal[]   = _T("Severity_Fatal");
      TCHAR SeverityWarning[] = _T("Severity_Warning");
      TCHAR SeverityInfo[]    = _T("Severity_Info");

      Kif::Win32::String *s = new Kif::Win32::String();
      switch(severity)
      {
         case Severity_Fatal:
            s->Copy(SeverityFatal,SizeOf(SeverityFatal));
            break;
         case Severity_Warning:
            s->Copy(SeverityWarning,SizeOf(SeverityWarning));
            break;
         case Severity_Info:
            s->Copy(SeverityInfo,SizeOf(SeverityInfo));
            break;
         default:
            s->Copy(SeverityUnknown,SizeOf(SeverityUnknown));
            break;
      }
      return(s);
   }  // end of GetSeverityString

   // --------------------------------------------------------------------------
   static void WriteMessage(
      TCHAR *logPath, TCHAR *location, TCHAR *operation, TCHAR *message,
      SeverityLevel severity, LogOutputOption outputTo);
}  ;

// -----------------------------------------------------------------------------

class LogMessage
{
public:

   Kif::Win32::DateTime DateTime;
   SeverityLevel Severity;
   Kif::Win32::String Location;
   Kif::Win32::String Message;

   // use the "Appendix" to store any other data that you may want to store as
   // part of your logged messages beyond those pieces of information in the
   // 'LogMessage' (in Xml format).
   Kif::Win32::String XmlAppendix;

   LogMessage()
   {
      Severity = Severity_None;
   }

   void Clear()
   {
      Severity = Severity_Unknown;
      Message.Dispose();
      Location.Dispose();
      XmlAppendix.Dispose();
   }  // end of Clear

   Kif::Win32::String *ToXmlString()
   {
      TCHAR *loc = Location.GetLength() > 0 ? Location.GetBuffer() : NULL;
      TCHAR *mes = Message.GetLength() > 0 ? Message.GetBuffer() : NULL;
      return(Log::ToXmlLogEntry(loc,mes,Severity));
   }  // end of ToXmlString

}  ;  // end of LogMessage

typedef ::std::list<LogMessage> LogMessageList;

class LogMessages
{
private:
   LogMessageList list;
   LogMessageList::iterator i;
   int currrentPosition;

public:

   LogMessage Item;
   int Count;

   LogMessages()
   {
      Count = 0;
      currrentPosition = -2;
      Item.Clear();
   }  // end of ResultMessages (ctor)

   inline bool Open()
   {
      i = list.begin();
      currrentPosition = -1;
      return(i != list.end());
   }  // end of OpenReader

   bool Read()
   {
      if (currrentPosition == -2)
         return(false);
      if (currrentPosition != -1)
         i++;
      currrentPosition++;
      if (currrentPosition >= Count)
      {
         Close();
         Item.Clear();
         return(false);
      }
      bool notDone = i != list.end();
      if (notDone)
         Item = *i;
      return(notDone);
   }  // end of Read

   inline void Close()
   {
      currrentPosition = -2;
      Item.Clear();
   }  // end of OpenReader

   inline void Clear()
   {
      Count = 0;
      list.clear();
   }  // end of Clear

   inline void Add(LogMessage &message)
   {
      Count++;
      list.insert(list.end(),message);
   }  // end of Add

   inline void Add(
      TCHAR *message,
      TCHAR *location,
      SeverityLevel severity)
   {
      LogMessage mess;
      mess.Message.Copy(message);
      mess.Location.Copy(location);
      mess.Severity = severity;
      Add(mess);
   }  // end of Add

   inline void Add(
      Kif::Win32::String &message,
      SeverityLevel severity)
   {
      LogMessage mess;
      mess.Message.Copy(message.GetBuffer(),message.GetLength());
      mess.Severity = severity;
      Add(mess);
   }  // end of Add

   inline void Add(
      Kif::Win32::String &message)
   {
      LogMessage mess;
      mess.Message.Copy(message.GetBuffer(),message.GetLength());
      mess.Severity = Severity_None;
      Add(mess);
   }  // end of Add

   inline void Add(
      TCHAR *message,
      TCHAR *location)
   {
      LogMessage mess;
      mess.Message.Copy(message);
      mess.Location.Copy(location);
      mess.Severity = Severity_None;
      Add(mess);
   }  // end of Add

   inline void Add(
      TCHAR *message)
   {
      LogMessage mess;
      mess.Message.Copy(message);
      mess.Severity = Severity_None;
      Add(mess);
   }  // end of Add

   Kif::Win32::String *ToXmlString();
}  ;  // end of ResultMessages

}  // end of Kif::Win32::Diagnostics
}  // end of Kif::Win32
}  // end of Kif

